#pragma once
#include<iostream>
#include<queue>
#include<pthread.h>

namespace sola_blockqueue
{
    template<class T>
    class BlockQueue
    {
    public:
        BlockQueue(const int cap = 5)
        :_cap(cap)
        {
            pthread_mutex_init(&mutex,nullptr);
            pthread_cond_init(&full,nullptr);
            pthread_cond_init(&empty,nullptr);
        }
        ~BlockQueue()
        {
            pthread_mutex_destroy(&mutex);
            pthread_cond_destroy(&full);
            pthread_cond_destroy(&empty);
        }


        void Push(const T&in )           //生产
        {
            LockQueue();
            while(IsFull())
            {
                ProducterWait();
            }
            bq.push(in);
            if(bq.size()>_cap/2)
            ConsumerBroadcast();
            //可以设计策略，如放的量过了一半再唤醒消费者  
            UnLockQueue();

        }
        void Pop(T* out)       //消费     输出型参数用指针  输入输出用&    输入const &
        {
            LockQueue();
            while(IsEmpty())
            {
                ConsumerWait();
            }
            *out = bq.front();
            bq.pop();
            //可以设计策略，剩余量小于一半时再唤醒生产者
            if(bq.size()<_cap/2)
            ProducterBroadcast();
            UnLockQueue();
        }

    private:
    bool IsFull()
    {
        return bq.size()==_cap;
    }
    bool IsEmpty()
    {
        return bq.size()== 0;
    }

    void LockQueue()
    {
        pthread_mutex_lock(&mutex);
    }
    void UnLockQueue()
    {
        pthread_mutex_unlock(&mutex);
    }

    void ProducterWait()
    {
        //1.调用时，自动释放mutex，再挂起
        //2.返回时，首先申请mutex,拿到锁后才能返回。
        pthread_cond_wait(&full,&mutex);
    }

    void ConsumerWait()
    {
        pthread_cond_wait(&empty,&mutex);
    }

    void ProducterSignal()
    {
        pthread_cond_signal(&full);
    }

    void ConsumerSinal()   
    {
        pthread_cond_signal(&empty);
    }

    void ProducterBroadcast()
    {
        pthread_cond_broadcast(&full);
    }

    void ConsumerBroadcast()   
    {
        pthread_cond_broadcast(&empty);
    }

    private:
    std::queue<T> bq;  //我们的阻塞队列
    int _cap;           //容量上线
    pthread_mutex_t mutex;   //保护临界资源的锁
    //生产满了的时候就停止生产，让消费者来消费   消费空了，就生产 
    pthread_cond_t full;    //bq满了，生产者等待
    pthread_cond_t empty;   //bq空了  消费者等待
    };





}